package com.yunfinal.api.service.doc;

import com.alibaba.fastjson.JSONObject;
import com.jfinal.log.Log;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * 测试请求, 生成文档 工具类
 */
public class ApiDataHttp {
    public static ApiDataHttp ME = new ApiDataHttp();

    protected String domainName;
    protected Log log;


    public ApiDataHttp() {
        this("http://127.0.0.1:8080");
    }

    public ApiDataHttp(String domainName) {
        this.domainName = domainName;
        this.log = Log.getLog(this.domainName);
    }

    /**
     * 创建一个参数集合
     *
     * @return
     */
    public ApiDocData newApiDocData() {
        return new ApiDocData();
    }

    /**
     * 单测试,请求成功后直接控制台输出结果
     *
     * @param actionKey 请求的action
     * @param kv        参数附带说明
     */
    public void doc(String actionKey, ApiDocData kv) {
        doc(actionKey, kv, false);
    }

    protected void doc(String actionKey, ApiDocData kv, boolean generateMd) {
        String jsonStr = post(actionKey, kv);
        jsonStr = formatJson(jsonStr);
        if (generateMd) {
            generateMd(actionKey, kv, jsonStr);
        }
        printJson(jsonStr);
    }

    /**
     * 单测试,请求成功后直接控制台输出结果，并写入文档
     *
     * @param actionKey 请求的action
     * @param kv        参数附带说明
     */
    public void docGenerate(String actionKey, ApiDocData kv) {
        doc(actionKey, kv, true);
    }

    protected void generateMd(String actionKey, ApiDocData kv, String jsonStr) {
        JSONObject data = new JSONObject();
        data.put("actionKey", actionKey);
        data.put("cover", true);
        JSONObject d = new JSONObject();
        data.put("d", d);
        d.put("para", kv);
        kv.paraStr(formatJson(kv.toJSONString()));
        d.put("ret", jsonStr);

        ApiDocService.ME.details(data);
    }

    /**
     * 请求后把结果转换为 JSONObject 对象 返回， 一般用于联动测试
     */
    public JSONObject postToJson(String actionKey, ApiDocData kv) {
        String ret = post(actionKey, kv);
        return JSONObject.parseObject(ret);
    }

    public String post(String actionKey, ApiDocData kv) {
        String jsonString = kv.toJSONString();
        StringBuilder ret = new StringBuilder();
        try {
            //url地址
            URL url = new URL(domainName.concat(actionKey));

            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setRequestMethod("POST");
            connection.setUseCaches(false);
            connection.setInstanceFollowRedirects(true);
            connection.setRequestProperty("Content-Type", "application/json");
            connection.connect();

            try (OutputStream os = connection.getOutputStream()) {
                os.write(jsonString.getBytes("UTF-8"));
            }
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(connection.getInputStream()))) {
                String lines;
                while ((lines = reader.readLine()) != null) {
                    lines = new String(lines.getBytes(), "UTF-8");
                    ret.append(lines);
                }
            }
            connection.disconnect();
        } catch (FileNotFoundException e) {
            log.error("检查一下请求路径的拼写，检查服务器上是否注册了控制器，再不行就重启一下服务器");
        } catch (Exception e) {
            log.error("检查服务器是否启动了", e);
        }
        return ret.toString();
    }

    protected void printJson(String jsonStr) {
        System.out.println(jsonStr);
    }

    protected String formatJson(String jsonStr) {
        if (null == jsonStr || "".equals(jsonStr))
            return "";
        StringBuilder sb = new StringBuilder();
        char last = '\0';
        char current = '\0';
        int indent = 0;
        boolean isInQuotationMarks = false;
        for (int i = 0; i < jsonStr.length(); i++) {
            last = current;
            current = jsonStr.charAt(i);
            switch (current) {
                case '"':
                    if (last != '\\') {
                        isInQuotationMarks = !isInQuotationMarks;
                    }
                    sb.append(current);
                    break;
                case '{':
                case '[':
                    sb.append(current);
                    if (!isInQuotationMarks) {
                        sb.append('\n');
                        indent++;
                        addIndentBlank(sb, indent);
                    }
                    break;
                case '}':
                case ']':
                    if (!isInQuotationMarks) {
                        sb.append('\n');
                        indent--;
                        addIndentBlank(sb, indent);
                    }
                    sb.append(current);
                    break;
                case ',':
                    sb.append(current);
                    if (last != '\\' && !isInQuotationMarks) {
                        sb.append('\n');
                        addIndentBlank(sb, indent);
                    }
                    break;
                default:
                    sb.append(current);
            }
        }

        return sb.toString();
    }

    protected void addIndentBlank(StringBuilder sb, int indent) {
        for (int i = 0; i < indent; i++) {
            sb.append('\t');
        }
    }
}
